package Game;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Random;
import java.util.Scanner;
import java.util.StringTokenizer;
import java.util.Vector;

import javax.swing.JOptionPane;

import Card.*;
import GameElement.*;
import PlayerElement.AnalysisReport;


public class Game {
	
	private String[] game_player_roles = { "SON", "DAUG.", "FATHER", "MOTHER", "GRANDMA", "GRANDPA" };	// State the roles that game player can be act as.	
	private boolean isGameContinue = false;																// Check the game is end or not
	private GameBoard game_board;																		// Create a variable of game board
	private GamePlayer[] game_players;																	// Create a array to store all game players
	private GamePlayer current_player;																	// Create a variable to identify current turn player 
	private Vector card_deck;																			// Create a vector list to store all cards
	private Vector player_queue;																		// Create a vector list to state the queue of player turns
	private final int goalScore = 1000;																	// State the goal score that players need to achieve
	private GameIO gameIO;																				// Create a variable of game input/output
	private EventExecution eventExe;																	// Create a variable of event execution
	private enum cardType { ACTION, SAY, EVENT; }														// Create a enum type to identify the card type

	/**
	 * Constructor to initialize all variables. Such as,
	 * Game IO, Game Board, Game Players, Game Cards and Game End.
	 * @param cardtxt
	 * @throws IOException
	 */
	public Game(String cardtxt) throws IOException{
		isGameContinue = true;
		gameIO = new GameIO(new Scanner(System.in));
		game_board = new GameBoard(11);
		initGamePlayers();
		gameIO.validateCardtxt(initGameCard(cardtxt),cardtxt);
	}

	/**
	 * Loop to print the game board and request user input.
	 * @throws IOException
	 */
	public void startGame() throws IOException{
		do {
			game_board.printBoardConsole(game_players);
			optionsMenu(11);
		} while (isGameContinue);
	}
	
	/**
	 * Initialize all game players.
	 * Put all player on the queue, and set players roles.
	 * @throws IOException
	 */
	public void initGamePlayers() throws IOException {
		player_queue = new Vector();
		int numOfPlayers = gameIO.getNumberOfPlayers();
		game_players = new GamePlayer[numOfPlayers];
		for (int i = 0; i < game_players.length; i++) {
			String player_name = gameIO.getPlayersName(i);
			int roleAlias = gameIO.getRole(game_player_roles);
			String roles = game_player_roles[roleAlias];
			game_players[i] = new GamePlayer(player_name, roles);
			switch (roleAlias) {
				case 0: game_players[i].setInitScore(300); break;
				case 1: game_players[i].setInitScore(300); break;
				case 2: game_players[i].setInitScore(100); break;
				case 3: game_players[i].setInitScore(100); break;
				case 4: game_players[i].setInitScore(200); break;
				case 5: game_players[i].setInitScore(200); break;
			}
			player_queue.addElement(game_players[i]);	
		}
		current_player = (GamePlayer) player_queue.get(0);
	}
	
	/**
	 * Return player queue of game
	 * @return Player Queue
	 */
	public Vector getPlayerQueue(){
		return player_queue;
	}
	
	/**
	 * Initialize game cards
	 * Read card information from the external .txt file
	 * If it is ACTION CARD, initialize the card in Act card object
	 * If it is SAY CARD, initialize the card in Say card object
	 * If it is EVENT CARD, initialize the card in Event card object
	 * @param sources
	 * @throws FileNotFoundException	If .txt file is not found.
	 * @throws IOException				If .txt file read information found incorrect.
	 * @return Game cards initialization successful or not
	 */
	public boolean initGameCard(String sources) {
		card_deck = new Vector();
		try {
			GameCard card = null;
			BufferedReader br = new BufferedReader(new FileReader(sources));
			String line = "";
			while ((line = br.readLine()) != null) {
				StringTokenizer st = new StringTokenizer(line);
				String card_type = st.nextToken();
				cardType test = cardType.valueOf(card_type);
				switch (test) {
				case ACTION:
					card = new ActCard(new String[] { st.nextToken(),
							st.nextToken().replace('_', ' '), st.nextToken() });
					break;
				case SAY:
					card = new SayCard(new String[] { st.nextToken(),
							st.nextToken().replace('_', ' '), st.nextToken() });
					break;
				case EVENT:
					String[] card_info = new String[50];
					card_info[0] = st.nextToken();
					card_info[1] = st.nextToken().replace('_', ' ');
					for (int i = 2; i < 50; i++) {
						card_info[i] = st.nextToken().replace('_', ' ');
					}
					card = new EventCard(card_info);
					break;
				}
				card_deck.add(card);
			}
		} catch (FileNotFoundException e) {
			return false;
		} catch (IOException e) {
			return false;
		}
		return true;
	}
	
	/**
	 * Game Player select the options 
	 * If player select 1 ->	Roll dice and execute the event after draw card
	 * If player select 2 ->	End turn
	 * @param diceCount
	 * @throws IOException		If input is CHARACTER/SYMBOL
	 */
	public void optionsMenu(int diceCount) throws IOException {
		switch (gameIO.getActionOfOptionMenu(current_player)) {
			case 1:
				rollDice(diceCount);
				eventExe = new EventExecution(current_player,game_players,card_deck,gameIO);
				endTurn();
				break;
			case 2:
				current_player.modifyScore(-50);
				endTurn();
				break;
		}
	}

	/**
	 * Game player roll the dice
	 * @param randomCount
	 */
	private void rollDice(int randomCount) {
		Random random = new Random();
		int points = 0;
		points = random.nextInt(randomCount)+2;
		current_player.modifyPosition(points);
		gameIO.printDiceAndPosition(points,current_player.getPosition());
		
	}

	/**
	 * Game player end turn and switch to next player on queue.
	 */
	public void endTurn() {
		gameIO.printEndTurn(current_player.getGamePlayerName());
		GamePlayer temp = (GamePlayer) player_queue.get(0);
		player_queue.addElement(temp);
		player_queue.remove(0);
		current_player = (GamePlayer) player_queue.get(0);
		isGameContinue = isGameEnd();
	}

	/**
	 * Check the players score.
	 * If each player score > goal score = win the game
	 * If one of player score < 0 = lose the game
	 * @return Game end is true or not
	 */
	private boolean isGameEnd() {
		int count = 0;
		for(int i = 0; i < game_players.length;i++){
			if(game_players[i].getScore() >= goalScore){
				count++;
				if(count == game_players.length){
					gameIO.printWinGame(goalScore);
					printPlayersReport(game_players);
					return false;
				}
			}
			if(game_players[i].getScore() < 0){
				gameIO.printLoseGame(game_players[i].getGamePlayerName());
				printPlayersReport(game_players);
				return false;
			}
		}
		return true;
	}
	
	/**
	 * Print all the players performance report.
	 * @param game_players
	 */
	public void printPlayersReport(GamePlayer[] game_players) {
		for (int i = 0; i < game_players.length; i++)
			game_players[i].getPerformaceReport();
	}
	
	/**
	 * Initialize Game and start the game
	 * @param args
	 * @throws Exception	If there is any errors
	 */
	public static void main(String[] args) throws Exception {
		Game game = new Game("card.txt");
		game.startGame();
	}

}